
/* CalSyncUm 
 * Copyright (c) 2006,2007 Arthur van Bunningen
 * Based on L-dopa Calendar Sync, Copyright (c) 2006 Richard Stoner
 * 
 * This program is in no way affiliated with Google, Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/



using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Net;
using System.IO;
using Microsoft.WindowsMobile.PocketOutlook;




namespace calsyncum
{
    public partial class GoAmi : Form
    {
        //global classes and utilities
        
        SyncList syncList;
        GoogleInterface googleInterface;
        OutlookInterface outlookInterface;        
        public const string VERSION = "0.23";                
        public const string SYNCFILE = "calsyncum_data.xml";
        public const string CONFIGFILE = "calsyncum_config.xml";
        public const string GOOGLERECURRENCE = "[CalSyncUm: Recurring appointment on Google - do not edit]";        
        public String gusername;
        public String gpassword;        
        
        
        public GoAmi()
        {
            InitializeComponent();
            statusText.ScrollBars = ScrollBars.Vertical;
            syncList = new SyncList(this, SYNCFILE);
            gusername = syncList.getGUsername();
            gpassword = syncList.getGPassword();
        }

        
        public bool outlookToGoogleOverwrite()
        {
            log("Start download Outlook", 5);
            debug("outlookToGoogleOverwrite");
            outlookInterface.downloadEvents();
            log("Start download Google", 10);
            //licence url check            
            if (googleInterface.isInitialized)
            {                
                debug("Load sync data.");                
                

                //attempt to login to google
                debug("Start login at Google");
                if (!googleInterface.login())
                {
                    debug("login failed");
                    return false;

                }
                else
                {
                    debug("login successful");
                }
                
                //attempt to download the feed from google
                debug("Download google data");
                log("Download Google data", 15);                
                if (!googleInterface.downloadEvents())
                {
                    debug("Error downloading google data");
                    return false;
                }
                else
                {
                    debug("Google data successfully downloaded");
                }
                log("Delete Google data", 15);        
                debug("Starting delete on google");
                for (int j = 0; j < googleInterface.events.Count; j++)
                {
                    CalendarEvent googleEvent = googleInterface.events[j];
                    if (!(googleInterface.deleteongoogle(googleEvent.googleid)))
                    {
                        debug("Delete on google failed");
                        //return false;
                    }
                }
            }
            debug("Resetting sync file.");
            File.Delete(SYNCFILE);
            syncList = new SyncList(this, SYNCFILE);
            syncList.storeLogin(gusername, gpassword);            
            debug("Adding Outlook data to Google");
            log("Add data to Google", 25);        
            for (int Ocount = 0; Ocount < outlookInterface.events.Count; Ocount++)
            {

                CalendarEvent outlookEvent = outlookInterface.events[Ocount];
                debug("O:found: " + outlookEvent.subject);
                string returnedGID = googleInterface.posttogoogle(outlookEvent);
                if (String.IsNullOrEmpty(returnedGID))
                {
                    debug("Add to google failed");
                }
                else
                {
                    syncList.addBoth(returnedGID, outlookEvent.outlookid);
                }
            }
            syncList.save();
            debug("Outlook to google successfull");
            log("Outlook to google successfull", 100);
            return true;
        }

        public bool googleToOutlookOverwrite()
        {
            debug("Download Outlook data");
            log("Download Outlook data", 5);
            outlookInterface.downloadEvents();
            log("Download Google data", 15);
            if (googleInterface.isInitialized)
            {

               
                

                //attempt to login to google
                debug("Start login at Google");
                if (!googleInterface.login())
                {
                    debug("login failed");
                    return false;

                }
                else
                {
                    debug("login successful");
                }
                
                //attempt to download the feed from google
                debug("Download google data");
                if (!googleInterface.downloadEvents())
                {       
                    debug("Error downloading google data");
                    return false;
                }
                else
                {
                    debug("Google data successfully downloaded");
                }
            }
            debug("Start delete on outlook");
            log("Delete data on outlook", 25);
            for (int Ocount = 0; Ocount < outlookInterface.events.Count; Ocount++)
            {
                CalendarEvent outlookEvent = outlookInterface.events[Ocount];
                outlookInterface.deleteOnOutlook(outlookEvent.outlookid);
            }
            
            debug("Resetting sync file.");
            File.Delete(SYNCFILE);
            syncList = new SyncList(this, SYNCFILE);
            syncList.storeLogin(gusername, gpassword); 
            debug("Adding Google data to Outlook");
            log("Add Google to outlook data", 35);
            for (int j = 0; j < googleInterface.events.Count; j++)
            {
                CalendarEvent googleEvent = googleInterface.events[j];
                debug("G:found: " + googleEvent.subject);
                if (googleEvent.hasrecurrence)
                {
                    // If recurring event we keep it outside the administration
                    googleEvent.description = googleEvent.description + " " + GOOGLERECURRENCE;
                    string returnedOID = outlookInterface.posttooutlook(googleEvent).ToString();
                }
                else
                {
                    string returnedOID = outlookInterface.posttooutlook(googleEvent).ToString();
                    syncList.addBoth(googleEvent.googleid, returnedOID);
                }
            }
            syncList.save();
            debug("Google to outlook successfull");
            log("Google to outlook successful", 100);
            return true;

        }

        



        //this is the final thread, but must first work on parsing input and outputs from google
        // recurrence betekend: niet deleten op google als hij op outlook gedelete is..
        //                          wel deleten op outlook als weg op google
        //                      aanpassen update: altijd alleen van google naar outlook 
        // aanpassen geteventfrom id in googleinterface..
        public bool syncthread()
        {
            log("Start synchronization", 5);
            if (googleInterface.isInitialized)
            {
                
                //proceed to 2-way sync
                debug("Load sync data.");                
                DateTime lastUpdated = syncList.getLastModifiedDate();

                //attempt to login to google
                log("Start login at Google", 7);
                debug("Start login at Google");
                if (!googleInterface.login())
                {
                    debug("login failed");
                    return false;
                   
                }
                else
                {
                    debug("login successful");
                }

                log("Download from Google", 10);
                //attempt to download the feed from google
                debug("Download google data");
                if (!googleInterface.downloadEvents())
                {
                    debug("Error downloading google data");
                    return false;
                }
                else
                {
                    debug("Google data successfully downloaded");                    
                }
                log("Delete recurring from G on O", 15);
                //First delete google recurrence appointments
                outlookInterface.deleteOnDescription(GOOGLERECURRENCE);
                
                //license check extra test
                
                // TODO: nicely hidden

                //adding any new events from the google feed
                debug("Download Outlook data (first time)");
                outlookInterface.downloadEvents();
                log("Loop through Google appointments", 20);
                for (int j = 0; j < googleInterface.events.Count; j++)
                {
                    CalendarEvent googleEvent = googleInterface.events[j];
                    debug("G:found: " + googleEvent.subject);
                    
                    String outlookId = syncList.getOutlookidForGid(googleEvent.googleid);
                    if (outlookId == null)
                    {
                        //no outlook id, but has google id -> new appointment -> add
                        debug("adding " + googleEvent.subject + " to the phone");
                        if (googleEvent.hasrecurrence)
                        {
                            // If recurring event we keep it outside the administration
                            googleEvent.description = googleEvent.description + " " + GOOGLERECURRENCE;
                            string returnedOID = outlookInterface.posttooutlook(googleEvent).ToString();
                        }
                        else
                        {
                            string returnedOID = outlookInterface.posttooutlook(googleEvent).ToString();
                            syncList.addBoth(googleEvent.googleid, returnedOID);
                        }
                        
                    }
                    else
                    {
                        // ok we have an outlook id.. but it could be deleted locally..
                        CalendarEvent outlookEvent = outlookInterface.getEventFromId(outlookId);
                        if (outlookEvent == null)
                        {
                            debug("Outlookevent was del since last sync: delete on google");
                            if (!(googleInterface.deleteongoogle(googleEvent.googleid)))
                            {
                                debug("Delete on google failed");
                                //return false;
                            }
                            syncList.deletebyGid(googleEvent.googleid);                        
                        }
                        
                                               

                    }
                }
                syncList.save();
                

                #region Processing phone calendar items

                try
                {
                    debug("Download Outlook data (refresh)");
                    log("Loop through Outlook appointments", 60);
                    outlookInterface.downloadEvents();
                    
                    for (int Ocount = 0; Ocount < outlookInterface.events.Count; Ocount++)
                    {

                        CalendarEvent outlookEvent = outlookInterface.events[Ocount];
                        debug("O:found: " + outlookEvent.subject);
                        // only test appointments that do not result from recurrence..
                        if (outlookEvent.description.IndexOf(GOOGLERECURRENCE) == -1)
                        {
                            String googleid = syncList.getGoogleidForOid(outlookEvent.outlookid);
                            if (googleid == null)
                            {
                                // did not find google id: it is a new appointment: should add to google                            
                                debug("No google id in sync: new : Add");
                                string returnedGID = googleInterface.posttogoogle(outlookEvent);
                                if (String.IsNullOrEmpty(returnedGID))
                                {
                                    // (might be out of range)
                                    debug("Adding to google failed");
                                }
                                else
                                {
                                    syncList.addBoth(returnedGID, outlookEvent.outlookid);
                                }

                            }
                            else
                            {
                                // we have a google id from last sync..


                                // TODO: 2 dingen: getEventFromId mag exceptie gooien, want ontbetrouwbaar als buiten range
                                // Not delete on outlook (before date), However it should delete the event from the synclist
                                CalendarEvent googleEvent = googleInterface.getEventFromId(googleid);
                                if (googleEvent == null)
                                {
                                    if (googleInterface.isOutOfQueryRange(outlookEvent))
                                    {
                                        // No google id in downloaded events, but is was out of range anyway..
                                    }
                                    else
                                    {
                                        debug("No google id at google : deleted : Del");
                                        outlookInterface.deleteOnOutlook(outlookEvent.outlookid);
                                    }
                                    syncList.deletebyOid(outlookEvent.outlookid);
                                }
                                else
                                {
                                    //@@@ this seems not to work for all day events, when want on update on google..
                                    //@@@ TODO: max-results. hoger dan 25, maar wel met min-date.. recursie moeten we
                                    //er echter waarschijnlijk wel uithalen anders krijgen we conflicten..
                                    // max-results lijkt prima te werken, moeten wel een oplossing bij verschuivend windws, dat
                                    // niet afspraken automatisch in outlook worden verwijdert omdat 
                                    // misschien door "minimal date" te gebruiken voor deletion..?
                                    bool needtoupdate = false;
                                    if (outlookEvent.subject != googleEvent.subject)
                                    {
                                        needtoupdate = true;
                                    }
                                    if (outlookEvent.location != googleEvent.location)
                                    {
                                        needtoupdate = true;
                                    }

                                    if ((outlookEvent.alldayevent == true) && (googleEvent.alldayevent == true))
                                    {
                                        if (outlookEvent.startTime.ToFileTimeUtc() != googleEvent.startTime.ToFileTimeUtc())
                                        {
                                            needtoupdate = true;
                                        }

                                    }
                                    else
                                    {
                                        if (outlookEvent.startTime.ToFileTimeUtc() != googleEvent.startTime.ToFileTimeUtc())
                                        {
                                            needtoupdate = true;
                                        }
                                        if (outlookEvent.endTime.ToFileTimeUtc() != googleEvent.endTime.ToFileTimeUtc())
                                        {
                                            needtoupdate = true;
                                        }
                                    }

                                    if (needtoupdate)
                                    {
                                        //check what to update
                                        debug("Should update");
                                        if (googleEvent.updatedOnGoogle.CompareTo(lastUpdated) < 0)
                                        {
                                            // googleEvent earlier updated than lastupdate -> should update on google
                                            debug("Google earlier: update on google");


                                            googleInterface.updateongoogle(googleEvent.googleid, outlookEvent);

                                            /*
                                            //delete it on google
                                            if (!(googleInterface.deleteongoogle(googleEvent.googleid)))
                                            {
                                                debug("Delete (to update) on google failed");
                                                return false;
                                            }

                                            //delete it from the synclist                              
                                            syncList.deletebyGid(googleEvent.googleid);

                                            string returnedGID = googleInterface.posttogoogle(outlookEvent);
                                            if (returnedGID == "")
                                            {
                                                debug("Post to google failed");
                                                return false;
                                            }
                                            syncList.addBoth(returnedGID, outlookEvent.outlookid);

                                            syncList.saveToFile(SYNCFILE);
                                             */

                                        }
                                        else
                                        {
                                            //google event later than last update update locally
                                            debug("Outlook earlier: update on outlook");
                                            outlookInterface.updateonoutlook(outlookEvent.outlookid, googleEvent);
                                            /*
                                            syncList.deletebyOid(outlookEvent.outlookid);


                                            outlookInterface.deleteOnOutlook(outlookEvent.outlookid);
                                        
                                            ItemId newItemId = outlookInterface.posttooutlook(googleEvent);
    
                                            syncList.addBoth(googleEvent.googleid, newItemId.ToString());                                       
                                             */
                                        } // google event later
                                    } // need to update
                                } // not google event = null
                            }
                        }
                        syncList.save();
                    }
                }
                catch (PocketOutlookException e)
                {
                    debug("Error resulting from outlook");
                    debug(e.Message);
                }

                #endregion

                syncList.save();
                log("Sync was successful", 100);
                debug("Sync was successful");

            }
            else
            {
                //display error message (method not found) and proceed to next
            }
            return true;

        }


        private void menuItem2_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        public void log(string input)
        {
            statusTextBox.Text = input;
            addGooLabel.Text = googleInterface.countAdd.ToString();
            updGooLabel.Text = googleInterface.countUpdate.ToString();
            delGooLabel.Text = googleInterface.countDel.ToString();
            addOutLabel.Text = outlookInterface.countAdd.ToString();
            updOutLabel.Text = outlookInterface.countUpdate.ToString();
            delOutLabel.Text = outlookInterface.countDel.ToString();
            //statusText.ScrollToCaret();      
            this.Refresh();
        }
        public void log(string input,int percentage)
        {
            statusTextBox.Text = input;
            progressBar1.Value = percentage;
            if ((googleInterface != null) && (outlookInterface != null))
            {
                addGooLabel.Text = googleInterface.countAdd.ToString();
                updGooLabel.Text = googleInterface.countUpdate.ToString();
                delGooLabel.Text = googleInterface.countDel.ToString();
                addOutLabel.Text = outlookInterface.countAdd.ToString();
                updOutLabel.Text = outlookInterface.countUpdate.ToString();
                delOutLabel.Text = outlookInterface.countDel.ToString();
            }
            //statusText.ScrollToCaret();            
            this.Refresh();
        }

        public void debug(string input)
        {
            statusText.Text = statusText.Text + input + "\r\n";
            
        }


        private void menuItem1_Click_1(object sender, EventArgs e)
        {
            

            if (initConnectors())
            {
                if (!(syncthread()))
                {
                    log("Sync failed (view log)", 0);
                }
            }
        }

        private void menuItem3_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void menuItem4_Click(object sender, EventArgs e)
        {
            if (initConnectors())
            {
                string b_message = "This will delete data on Google and overwrite this by Outlook data. OK?";
                DialogResult result = MessageBox.Show(b_message, "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                if (result == DialogResult.Yes)
                {
                    if (!(outlookToGoogleOverwrite()))
                    {
                        log("Outlook to Google failed (view log)", 0);
                    }
                }
            }
        }

        private void gooToOutMenuItem_Click(object sender, EventArgs e)
        {
            if (initConnectors())
            {
                string b_message = "This will delete data on Outlook and overwrite this by Google data. OK?";
                DialogResult result = MessageBox.Show(b_message, "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                if (result == DialogResult.Yes)
                {
                    if (!(googleToOutlookOverwrite()))
                    {
                        log("Google to Outlook failed (view log)", 0);
                    }
                }
            }
        }

        private bool initConnectors()
        {
            statusText.Text = "";
            debug("CalSyncUm: (c) 2006 APCp");
            debug("Based on l-dopa.sourceforge.net");
            debug("...but almost completely rewritten");

            /*
            debug(LICCHECKURL.IndexOf("?").ToString());
            debug(LICCHECKURL.IndexOf(VERSION).ToString());
            debug(URLNAAM.Length.ToString());
            debug(LICCHECKURL.IndexOf(URLNAAM).ToString());
           
             * 53, 62, 12, 11
             */          
           
            statusText.Visible = false;            
            syncList = new SyncList(this, SYNCFILE);
            gusername = syncList.getGUsername();
            gpassword = syncList.getGPassword();
            if ((gusername == null) || (gpassword == null))
            {
                MessageBox.Show("Google login settings unknown, please enter them.");
                setupPanel.Visible = true;
                return false ;
            }            
            setupPanel.Visible = false;
            this.Refresh();
            
            googleInterface = new GoogleInterface(this, gusername, gpassword );
            googleInterface.startMin = DateTime.Now.AddDays(-1);
            googleInterface.startMax = DateTime.Now.AddDays(90);
            outlookInterface = new OutlookInterface(this);
            return true;
        }

        private void linkLabel1_Click(object sender, EventArgs e)
        {
            statusText.Visible = true;
        }

        

        private void linkLabel2_Click(object sender, EventArgs e)
        {
            gusername = gusernameEditBox.Text;
            gpassword = gpasswordEditBox.Text;
            syncList.storeLogin(gusername, gpassword);
            syncList.save();
            setupPanel.Visible = false;
            this.Refresh();
        }

        private void editGooLoginMenuItem_Click(object sender, EventArgs e)
        {
            gusernameEditBox.Text = gusername;
            gpasswordEditBox.Text = gpassword;
            setupPanel.Visible = true;
        }

    }
}
